package com.sh15tech.mp.weixin.thread;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.jdbc.core.JdbcTemplate;

import com.sh15tech.mp.weixin.job.RemindJob;
import com.sh15tech.mp.weixin.modal.WxMessage;
import com.sh15tech.mp.weixin.modal.WxMessageRowMapper;
import com.sh15tech.mp.weixin.scan.WxSender;

public class WxRemindThread implements Runnable{

	private Logger log = LogManager.getLogger(getClass());
	
	private JdbcTemplate jdbcTemplate;
	
	public WxRemindThread(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	/**
	 * 处理实时消息
	 */
	private void processRealTimeMsg(){
		// 获取需要实时发送的消息
		String sql = "select m.*,u.openid from t_wx_message m, t_wx_user u where m.member_id=u.member_id and m.msg_state=0 and m.msg_type=0";
		
		List<WxMessage> msgs = jdbcTemplate.query(sql, new WxMessageRowMapper());
		
		if(!msgs.isEmpty()){
			List<String> succ = new ArrayList<>();
			
			// 发送之后更新发送状态
			for(WxMessage msg : msgs){
				if(WxSender.enrollment(msg)){
					msg.setMsgState(1);
					succ.add("update t_wx_message t set t.msg_state = 1 where t.id="+msg.getId());
				}
			}
			int[] result = jdbcTemplate.batchUpdate(succ.toArray(new String[succ.size()]));
			for(int res : result){
				log.info("execute update result : "+res);
			}
			
		}
	}
	
	private Scheduler scheduler = null;
	
	/**
	 * 处理计划任务
	 */
	private void processPlannedMsg(){
		// 获取需要实时发送的消息
		String sql = "select m.*,u.openid from t_wx_message m, t_wx_user u where m.member_id=u.member_id and m.msg_state=0 and m.msg_type=1 order by m.trigger_time";
		
		List<WxMessage> msgs = jdbcTemplate.query(sql, new WxMessageRowMapper());
		
		if(!msgs.isEmpty()){
			
			try {
				
				for(WxMessage msg : msgs){
					
					JobKey jobKey = new JobKey(msg.getId()+msg.getOpenId()+".job");
					TriggerKey triggerKey = new TriggerKey(msg.getId()+msg.getOpenId()+".trig");
					
					if(scheduler.checkExists(jobKey)){
						if(!msg.getTriggerTime().after(Calendar.getInstance().getTime())){
							scheduler.rescheduleJob(triggerKey, TriggerBuilder.newTrigger()
									.withIdentity(triggerKey)
									.startNow()
									.build());
						}else{
							scheduler.rescheduleJob(triggerKey, TriggerBuilder.newTrigger()
									.withIdentity(triggerKey)
									.startAt(msg.getTriggerTime())
									.build());
						}
					}else{
						
						JobDataMap map = new JobDataMap();
						
						Calendar ca = Calendar.getInstance();
						ca.setTime(msg.getTriggerTime());
						
						map.put("message", msg);
						map.put("jdbcTemplate", jdbcTemplate);
						
						JobDetail job = JobBuilder.newJob(RemindJob.class)
								.withIdentity(jobKey)
								.setJobData(map)
								.build();
						
						Trigger trigger = null;
						if(!msg.getTriggerTime().after(Calendar.getInstance().getTime())){
							trigger = TriggerBuilder.newTrigger()
									.withIdentity(triggerKey)
									.startNow()
									.build();
						}else{
							trigger = TriggerBuilder.newTrigger()
									.withIdentity(triggerKey)
									.startAt(msg.getTriggerTime())
									.build();
						}
						
						scheduler.scheduleJob(job, trigger);
					}
					
				}
				
			} catch (Exception e) {
				log.error("failed to build job", e);
			}
			
		}
	}
	
	@Override
	public void run() {
		
		try {
			System.setProperty("org.terracotta.quartz.skipUpdateCheck", "true");
			scheduler = StdSchedulerFactory.getDefaultScheduler();
			scheduler.start();
			log.info("job scheduler started");
		} catch (Exception e) {
			log.error("failed to start job scheduler", e);
		}
		
		while(true){

			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			// 处理实时消息
			processRealTimeMsg();
			
			// 处理计划任务
			processPlannedMsg();
			
		}
	}

}
